/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gylang.springmini.support;

import cn.hutool.core.clone.Cloneable;
import com.gylang.springmini.factory.ConfigurableBeanFactory;
import org.springframework.core.AttributeAccessor;
import org.springframework.lang.Nullable;

/**
 * BeanDefinition描述了一个bean实例，该实例具有属性值
 * 构造函数参数值和具体实现提供的进一步信息。
 * 这只是一个最小的接口:主要目的是允许{link BeanFactoryPostProcessor}内省和修改属性值和其他bean元数据
 *
 * @author gylang
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement, Cloneable<BeanDefinition> {

    /**
     * 单例
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * 多了
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    /**
     * 角色提示表明BeanDefinition是应用程序的主要部分。 通常对应于用户定义的 bean。
     */
    int ROLE_APPLICATION = 0;

    /**
     * 角色提示表明BeanDefinition是一些更大配置的支持部分，通常外部SUPPORT bean 被认为足够重要
     * 可以在更仔细地查看特定的而不是查看应用程序的整体配置时意识到。
     */
    int ROLE_SUPPORT = 1;

    /**
     * 角色提示指示BeanDefinition提供完全后台角色并且与最终用户无关。 在注册完全属于内部工作的 bean 时使用此提示
     */
    int ROLE_INFRASTRUCTURE = 2;


    // 属性修改


    /**
     * 设置父类名称
     *
     * @param parentName 父类名称
     */
    void setParentName(@Nullable String parentName);

    /**
     * 获取父级bean的定义
     *
     * @return 父级bean的名称
     */
    @Nullable
    String getParentName();

    /**
     * 设置bean的class类型
     *
     * @param beanClassName class类型
     * @see #setParentName
     * @see #setFactoryBeanName
     * @see #setFactoryMethodName
     */
    void setBeanClassName(@Nullable String beanClassName);

    /**
     * 设置类加载器
     * @param classLoader 类加载器
     */
    void setBeanClassClassLoad(@Nullable ClassLoader classLoader);

    /**
     * 获取类加载器
     * @return 类加载器
     */
    ClassLoader getBeanClassClassLoad();

    /**
     * 获取bean的class名称
     *
     * @return bean的class名称
     * @see #getParentName()
     * @see #getFactoryBeanName()
     * @see #getFactoryMethodName()
     */
    @Nullable
    String getBeanClassName();

    /**
     * 设置bean的目标范围 单例/原型
     *
     * @param scope {@link #SCOPE_SINGLETON} | {@link #SCOPE_PROTOTYPE}
     * @see #SCOPE_SINGLETON
     * @see #SCOPE_PROTOTYPE
     */
    void setScope(@Nullable String scope);

    /**
     * 返回此 bean 当前目标范围的名称，如果尚不知道，则返回null 。
     *
     * @return bean的目标范围
     */
    @Nullable
    String getScope();

    /**
     * 设置为懒加载
     *
     * @param lazyInit 是否为懒加载
     */
    void setLazyInit(Boolean lazyInit);

    /**
     * 判断是否为懒加载
     *
     * @return 判断是否为懒加载
     */
    boolean isLazyInit();

    /**
     * 获取是否设置懒加载的值
     * @return 是否懒加载的值
     */
    Boolean getLazyInit();

    /**
     * 设置这个 bean 依赖的 bean 的名称被初始化。 bean 工厂将保证这些 bean 首先被初始化。
     *
     * @param dependsOn 依赖的bean
     */
    void setDependsOn(@Nullable String... dependsOn);

    /**
     * 依赖的bean
     *
     * @return 依赖的bean
     */
    @Nullable
    String[] getDependsOn();

    /**
     * 设置此 bean 是否是自动装配到其他 bean 的候选者。
     * 请注意，此标志旨在仅影响基于类型的自动装配。 它不会影响按名称的显式引用，
     * 即使指定的 bean 没有被标记为自动装配候选者，也会被解析。
     * 因此，如果名称匹配，按名称自动装配仍然会注入一个 bean。
     *
     * @param autowireCandidate 是否为自动注入的候选者
     */
    void setAutowireCandidate(Boolean autowireCandidate);

    /**
     * 是否为自动注入的候选者
     *
     * @return 是否为自动注入的候选者
     */
    boolean isAutowireCandidate();

    /**
     * 设置此 bean 是否是主要的自动装配候选者。
     * 如果这个值对于多个匹配候选中的一个 bean 正好是true ，它将作为一个决胜者。
     *
     * @param primary 是否为主要候选者
     */
    void setPrimary(Boolean primary);

    /**
     * 是否为主要候选者
     *
     * @return 是否为主要候选者
     */
    boolean isPrimary();

    /**
     * 指定要使用的工厂 bean（如果有）。 这是要在其上调用指定工厂方法的 bean 的名称
     *
     * @param factoryBeanName 工厂方法初始化的bean的名称
     * @see #setFactoryMethodName
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    /**
     * 厂方法初始化的bean的名称
     *
     * @return 厂方法初始化的bean的名称
     */
    @Nullable
    String getFactoryBeanName();

    /**
     * 设置工厂方法初始化的方法名称
     *
     * @param factoryMethodName 工厂方法名称
     * @see #setFactoryBeanName
     * @see #setBeanClassName
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);

    /**
     * 工厂方法名称
     *
     * @return 工厂方法名称
     */
    @Nullable
    String getFactoryMethodName();

    /**
     * 构造函数参数列表
     *
     * @return 构造函数参数列表
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     * 获取参数值列表
     * @return 获取参数列表
     */
    Object[] getConstructorArgumentValuesArr();

    /**
     * 是否包含构造函数列表
     *
     * @return 是否存在构造函数列表
     * @since 5.0.2
     */
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }

    /**
     * Return the property values to be applied to a new instance of the bean.
     * <p>The returned instance can be modified during bean factory post-processing.
     *
     * @return the MutablePropertyValues object (never {@code null})
     */
    MutablePropertyValues getPropertyValues();

    /**
     * Return if there are property values defined for this bean.
     *
     * @since 5.0.2
     */
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }

    /**
     * 设置初始化方法
     *
     * @param initMethodName 初始化方法名称
     */
    void setInitMethodName(@Nullable String initMethodName);

    /**
     * 获取初始化方法名称
     *
     * @return 初始化方法名称
     */
    @Nullable
    String getInitMethodName();

    /**
     * 设置销毁方法名称
     *
     * @param destroyMethodName 销毁方法名称
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);

    /**
     * 获取销毁方法
     *
     * @return 销毁方法
     */
    @Nullable
    String getDestroyMethodName();

    /**
     * 为这个BeanDefinition设置角色提示。 角色提示为框架和工具提供了特定BeanDefinition的角色和重要性的指示。
     *
     * @param role 角色提示
     */
    void setRole(int role);

    /**
     * 获取这个BeanDefinition的角色提示
     *
     * @return role 角色提示
     */
    int getRole();


    // Read-only attributes


    /**
     * 是否为单例
     *
     * @return 是否为单例
     * @see #SCOPE_SINGLETON
     */
    boolean isSingleton();

    /**
     * 是否为多例
     *
     * @return 是否为多例
     * @see #SCOPE_PROTOTYPE
     */
    boolean isPrototype();

    /**
     * 是否为抽象类型
     *
     * @return 是否为抽象类型
     */
    boolean isAbstract();


    /**
     * 返回原始 BeanDefinition，如果没有则返回null 。
     * 允许检索装饰的 bean 定义（如果有）。
     * 请注意，此方法返回直接发起者。 遍历创建者链以找到用户定义的原始 BeanDefinition
     *
     * @return 返回原始 BeanDefinition
     */
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();

    /**
     * 合并父级beanDefinition
     * @param beanDefinition
     */
    void mergeSuperBeanDefinition(BeanDefinition beanDefinition);
}
